﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Threading;
using System.IO;
using System.IO.IsolatedStorage;
using Microsoft.Phone.Reactive;
// Microsoft.Phone.Shell provides access to the ApplicationBar
using Microsoft.Phone.Shell;
// System.Device.Location provides access to the Location Service
using System.Device.Location;
using PERenaud;

namespace PERenaud
{
    public partial class MapRadar : PhoneApplicationPage
    {
        private static bool fullScreen;

        ApplicationBarIconButton goToMainButton;

        // GeocoordinateWatcher for accessing the Location Service
        GeoCoordinateWatcher watcher;

        // useEmulation determines whether live or emulated data is used
        bool useEmulation = false;

        // Threads for position and status emulation and a static bool
        Thread positionEmulationThread;
        Thread statusEmulationThread;

        // sampleInterval determines how often, in milliseconds, the location data stream is sampled
        double sampleInterval = 1000;

        public MapRadar()
        {
            InitializeComponent();
            SupportedOrientations = SupportedPageOrientation.Portrait | SupportedPageOrientation.Landscape;

            // Initialize ApplicationBar
            ApplicationBar appBar = new ApplicationBar();
            appBar.IsVisible = true;
            this.ApplicationBar = appBar;

            //// emulationButton toggles between live and emulated data.
            //emulationButton = new ApplicationBarIconButton(new Uri("Buttons/emulation.png", UriKind.Relative));
            //emulationButton.Text = "emulate";
            //emulationButton.Click += new EventHandler(emulationButton_Click);
            //appBar.Buttons.Add(emulationButton);
            // emulationButton toggles between live and emulated data.

            goToMainButton = new ApplicationBarIconButton(new Uri("Buttons/start.png", UriKind.Relative));
            goToMainButton.Text = "emulate";
            goToMainButton.Click += new EventHandler(goToMainButton_Click);
            appBar.Buttons.Add(goToMainButton);


            // Set the informational TextBlocks to their initial value
            //emulationTextBlock.Text = useEmulation.ToString();

            useEmulation = App.emulationMode;
        }

        void goToMainButton_Click(object sender, EventArgs e)
        {
            NavigationService.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
        }

        private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {

            try
            {
                PageTitle.Text = App.currentFriend.FriendName;
            }
            catch (Exception)
            {
                
                throw;
            } 
            
            if (!useEmulation)
            {
                // If emulation is not used, instantiate the GeoCoordinateWatcher
                watcher = new GeoCoordinateWatcher(GeoPositionAccuracy.High);

                // FromEvent is used to obtain an Observable sequence of GeoPositionChangedEventArgs
                var locationEventAsObservable = Observable.FromEvent<GeoPositionChangedEventArgs<GeoCoordinate>>(
                    ev => watcher.PositionChanged += ev,
                    ev => watcher.PositionChanged -= ev);

                // To make the emulation code less complicated, get a stream of GeoCoordinate objects
                // from the stream of GeoPositionChangedEventArgs provided by the watcher.PositionChanged event.
                var geoCoordinatesFromEventArgs = from ev in locationEventAsObservable
                                                  select ev.EventArgs.Position.Location;

                // Sample the observable to return only one position per sample interval. The interval can be
                // adjusted by the sampleSlider in the UI.
                var sampledLocationEvents = geoCoordinatesFromEventArgs.Sample(TimeSpan.FromMilliseconds(sampleInterval));

                // Subscribe to the filtered Observable stream. InvokePositionChanged will be called each
                // time a new GeoCoordinate arrives in the stream.
                sampledLocationEvents.Subscribe(coordinate => InvokePositionChanged(coordinate));


                // Create an observable sequence of GeoPositionStatusChanged events.
                var locationStatusEventAsObservable = Observable.FromEvent<GeoPositionStatusChangedEventArgs>(
                    ev => watcher.StatusChanged += ev,
                    ev => watcher.StatusChanged -= ev);

                // For simplicity, create a stream of GeoPositionStatus objects from the stream of
                // GeoPositionStatusChangedEventArgs objects
                var statusFromEventArgs = from ev in locationStatusEventAsObservable
                                          select ev.EventArgs.Status;

                // Subscribe to the Observable  stream. InvokeStatusChanged will be called each time
                // a new GeoPositionStatus object arrives in the stream.
                statusFromEventArgs.Subscribe(status => InvokeStatusChanged(status));

                // Start the GeoCoordinateWatcher
                watcher.Start();
            }
            else
            {
                // If emulation is being used, start a new thread and run the StartStatusEmulation method.
                // When the emulated status becomes Ready, the position emulation thread is launched
                statusEmulationThread = new Thread(StartStatusEmulation);
                statusEmulationThread.Start();

            }

            // Replace the startButton with the pauseButton and set running to true
            App.running = true;
        }


        /// <summary>
        /// Called from the startButton click handler when emulation is turned on. This method
        /// calls EmulateLocationEvents which returns an IEnumerable sequence of GeoCoordinates.
        /// ToObservable converts this stream to an Observable sequence. Once the Observable is
        /// created, the method is the same as the non-emulation method. The stream is sampled
        /// and then Subscribe registers a handler that is called when new location data arrives.
        /// </summary>
        void StartPositionEmulation()
        {
            var emulatedEventsToObservable = App.EmulatePositionEvents().ToObservable();

            var sampledEvents = emulatedEventsToObservable.Sample(TimeSpan.FromMilliseconds(sampleInterval));

            sampledEvents.Subscribe(coordinate => InvokePositionChanged(coordinate));

        }
        /// <summary>
        /// Called from the startButton click handler when emulation is turned on. This method
        /// calls EmulateStatusEvents which returns an IEnumerable sequence of GeoPositionStatus
        /// objects. ToObservable converts this stream to an Observable sequence. The stream is 
        /// subscribed to, registering a handler that is called when new status data arrives.
        /// </summary>
        void StartStatusEmulation()
        {
            var statusEventsToObservable = App.EmulateStatusEvents().ToObservable();

            var statusFromEventArgs = from s in statusEventsToObservable
                                      select s.Status;

            statusFromEventArgs.Subscribe(status => InvokeStatusChanged(status));
        }

        /// <summary>
        /// InvokePositionChanged is called when new location data is available (either live
        /// or emulated). It uses BeginInvoke to call another handler on the Page's UI thread.
        /// </summary>
        /// <param name="coordinate"></param>
        void InvokePositionChanged(GeoCoordinate coordinate)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => PositionChanged(coordinate));
        }
        /// <summary>
        /// This is where the application responds to new location data. In this case, it simply
        /// displays the location information
        /// </summary>
        /// <param name="coordinate"></param>
        void PositionChanged(GeoCoordinate coordinate)
        {
            MyMap.Center = coordinate;
        }
        /// <summary>
        /// InvokeStatusChanged is called when new location status is available (either live
        /// or emulated). It uses BeginInvoke to call another handler on the Page's UI thread.
        /// </summary>
        /// <param name="status"></param>
        void InvokeStatusChanged(GeoPositionStatus status)
        {
            Deployment.Current.Dispatcher.BeginInvoke(() => StatusChanged(status));
        }

        /// <summary>
        /// This is where the application responds to new status information. In this case, it simply
        /// displays the location information.  If emulation is enabled and the status is Ready, a
        /// new thread is launched for position emulation. This mimics the behaviour of the live data,
        /// where location data doesn't arrive until the LocationService status is Ready.
        /// </summary>
        /// <param name="status"></param>
        void StatusChanged(GeoPositionStatus status)
        {
            // Display the current status
            //statusTextBlock.Text = status.ToString();
            if (status == GeoPositionStatus.NoData || status == GeoPositionStatus.Disabled)
                MessageBox.Show("Your GPS does not work right now. Please try again later or buy a real phone.");

            // If emulation is being used and the status is Ready, start the position emulation thread
            if (status == GeoPositionStatus.Ready && useEmulation)
            {

                positionEmulationThread = new Thread(StartPositionEmulation);
                positionEmulationThread.Start();
            }
        }

        private void ImagePreview_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (fullScreen == false)
            {
                VisualStateManager.GoToState(this, "FullScreenImage", true);
                fullScreen = true;
            }
            else
            {
                VisualStateManager.GoToState(this, "LittleImage", true);
                fullScreen = false;
            }
        }

 
    }
}